package gsw.demo.mvp.core.net.rxservice.rxbus;

import java.lang.reflect.Method;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

/**
 * 数据总线，用于给Presenter层提供Model，从而给Presenter层解耦
 */
public class RxBus {
    //使用双重检查+volatile，来创建单例
    private static volatile RxBus instance;
    //注册的Presenter层
    private Set<Object> presenters;

/**
 * 注册
 */
public synchronized void register(Object presenter) {
    presenters.add(presenter);
}

    /**
     * 取消注册
     */
    public synchronized void unRegister(Object subscriber) {
        presenters.remove(subscriber);
    }


    private RxBus() {
        //读写分离的集合
        presenters = new CopyOnWriteArraySet<>();
    }

    public static synchronized RxBus getInstance() {
        if (instance == null) {
            synchronized (RxBus.class) {
                if (instance == null) {
                    instance = new RxBus();
                }
            }
        }
        return instance;
    }

/**
 * 包装处理过程：指定线程，将得到的数据传给Presenter层
 *
 * @param function 用于从网络获取数据
 */
public void chainProcess(Function function) {
    Observable.just("")
            .subscribeOn(Schedulers.io())
            .map(function)//在这里进行网络访问
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer() {
                @Override
                public void accept(Object data) throws Exception {
                    //data会传送到总线上
                    if (data == null) {
                        return;
                    }
                    send(data);//把数据送到P层
                }
            });
}

    /**
     * 给Presenter层发送数据
     *
     * @param data 得到的网络数据
     */
    public void send(Object data) {
        for (Object subscriber : presenters) {
            //扫描注解,将数据发送到注册的对象标记方法的位置
            //subscriber表示层
            callMethodByAnnotation(subscriber, data);
        }
    }

    /**
     * 调用Presenter层处理数据的方法,根据@RegisterRxBus
     *
     * @param target Presenter层
     * @param data   得到的网络数据
     */
    private void callMethodByAnnotation(Object target, Object data) {
        //1.得到presenter中写的所有的方法
        Method[] methodArray = target.getClass().getDeclaredMethods();
        for (int i = 0; i < methodArray.length; i++) {
            try {
                if (methodArray[i].getAnnotation(RegisterRxBus.class) != null) {
                    //如果哪个方法上用了我们写的注解
                    //把数据传上去,再执行这个方法
                    Class paramType = methodArray[i].getParameterTypes()[0];
                    if (data.getClass().getName().equals(paramType.getName())) {
                        //执行
                        methodArray[i].invoke(target, new Object[]{data});
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}









